home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / cpp_libs / sos3-2.lha / src / cci / cci.c < prev    next >
C/C++ Source or Header  |  1992-01-23  |  35KB  |  1,067 lines

  1. /* --------------------------------------------------------------------------
  2.  * Copyright 1992 by Forschungszentrum Informatik (FZI)
  3.  *
  4.  * You can use and distribute this software under the terms of the licence
  5.  * you should have received along with this program.
  6.  * If not or if you want additional information, write to
  7.  * Forschungszentrum Informatik, "STONE", Haid-und-Neu-Strasse 10-14,
  8.  * D-7500 Karlsruhe 1, Germany.
  9.  * --------------------------------------------------------------------------
  10.  */
  11. // **************************************************************************
  12. // Module cci                       03/07/90                 Juergen Uhl (ju)
  13. // **************************************************************************
  14. // implements methods of classes: cci_Schema_impl, cci_Method_impl
  15. // **************************************************************************
  16.  
  17. // --------------------------------------------------------------------------
  18. // Tracing conventions:
  19. //    no tracing: string conversions for external types
  20. //    cci_VL      : symbol table patching
  21. //    cci_L      : hash table management, lookup of file names for load
  22. //    cci_M      : module initialization, local_... methods
  23. //    cci_H      : other methods
  24. // --------------------------------------------------------------------------
  25.  
  26. #include <sys/file.h>
  27. #include <osfcn.h>
  28. #include <libc.h>
  29. #include <string.h>
  30. #include <stream.h>
  31. #include <sys/resource.h> // getrlimit, setrlimit
  32. #include <sys/param.h>      // MAXPATHLEN
  33.  
  34. #ifdef GNU
  35. #include <unistd.h>      // SEEK_SET
  36.  
  37. #define CAN_LOAD_INCREMENTALLY
  38. #endif
  39.  
  40. #ifdef CAN_LOAD_INCREMENTALLY
  41. extern "C" {
  42. #include <a.out.h>
  43. }
  44.  
  45. #if defined(MIPSEL) || defined(USG)
  46.    #ifndef hpux
  47.       #define exec aouthdr
  48.       #define a_text text_start
  49.       #define a_data data_start
  50.    #endif
  51. #endif
  52.  
  53. #ifdef __pyr__
  54.    #define MUST_MPROTECT
  55.    #include <sys/mman.h>
  56.  
  57.    extern "C" {
  58.      int  mprotect (char *, int, int);
  59.    }
  60. #endif
  61. #endif CAN_LOAD_INCREMENTALLY
  62.  
  63. #include "sys.h"
  64. #include "sos.h"
  65. #include "smg.h"
  66. #include "cci_err.h"
  67. #include "trc_cci.h"
  68. #include "cci_sos.h"
  69.  
  70. typedef void (*vfct_ptr_t)();
  71.  
  72. // --------------------------------------------------------------------------
  73.  
  74. #ifdef CAN_LOAD_INCREMENTALLY
  75.  
  76. LOCAL const char *ENVVAR_NAME = "SOSINCLOAD";
  77.  
  78. LOCAL class cci_FileNames
  79. { public:
  80.    char     *executable,  // name of running executable
  81.         *symtab_file, // name of temporary file containing symbol table of
  82.               // the executable as extended by previous loads
  83.         *tmpfile,      // name of temporary file used to build the next
  84.               // version of symtab_file.
  85.         *stdlibs,      // linker options to load standard libraries
  86.         *linker,      // pathname of link editor
  87.         *crtmodule;   // pathname of object module containing the
  88.               // startup routine for incrementally loaded code
  89.    sos_Bool echo;      // flag: echo files to be loaded
  90.  
  91.    cci_FileNames ();
  92.    ~cci_FileNames ();
  93. } cci_file_names;
  94.  
  95. cci_FileNames::cci_FileNames () {} // compiler error ??? destructor is only
  96.                    // called, if construtor is defined
  97. cci_FileNames::~cci_FileNames ()
  98. {  if (symtab_file) unlink (symtab_file);
  99.    if (tmpfile)     unlink (tmpfile);
  100. }
  101. #endif CAN_LOAD_INCREMENTALLY
  102.  
  103.  
  104. // **************************************************************************
  105. void cci_init (char** argv)
  106. // **************************************************************************
  107. {  T_PROC ("cci_init")
  108.    TT (cci_M, T_ENTER);
  109.  
  110. #ifndef CAN_LOAD_INCREMENTALLY
  111.    TT (cci_M, T_LEAVE);
  112. #else
  113.     // argv[0] is expected to contain either the absolute pathname of
  114.     // the executable, or a relative pathname anchored at the current
  115.     // working directory.
  116.    if (*argv[0] EQ '/')
  117.       cci_file_names.executable = strdup (argv[0]);
  118.    else
  119.    {  char cwd[MAXPATHLEN];
  120.       smg_String tmp = smg_String(getwd(cwd)) + "/" + argv[0];
  121.  
  122.       cci_file_names.executable = tmp.make_Cstring (SMG_TRANSFER);
  123.    }
  124.  
  125.    sos_Bool do_default_init = TRUE;
  126.    char     *settings       = getenv (ENVVAR_NAME);
  127.  
  128.    if (settings)
  129.    {  sos_Bool is_ok;
  130.       if (is_ok = (sos_Bool) (*settings EQ '+'  OR  *settings EQ '-'))
  131.       {  cci_file_names.echo = (sos_Bool)(*settings EQ '+');
  132.  
  133.      while (*(++ settings)  AND  *settings EQ ' ')
  134.         ;
  135.      if (*settings EQ EOS)
  136.         is_ok = FALSE;
  137.      else
  138.      {  for (char *start = settings;
  139.          *settings AND *settings != ' ';
  140.          ++ settings)
  141.            ;
  142.         int len = settings - start;
  143.         cci_file_names.linker = strncpy (new char[len+1], start, len);
  144.         cci_file_names.linker[len] = EOS;
  145.  
  146.         while (*(++ settings)  AND  *settings EQ ' ')
  147.            ;
  148.         if (*settings EQ EOS)
  149.            is_ok = FALSE;
  150.         else
  151.         {  for (start = settings;
  152.             *settings AND *settings != ' ';
  153.             ++settings)
  154.           ;
  155.            len = settings - start;
  156.            cci_file_names.crtmodule = strncpy (new char[len+1], start, len);
  157.            cci_file_names.crtmodule[len] = EOS;
  158.  
  159.            cci_file_names.stdlibs = strdup (settings);
  160.         }
  161.      }
  162.       }
  163.       if (is_ok)
  164.      do_default_init = FALSE;
  165.       else
  166.          err_raise (err_USE, err_CCI_WRONG_INIT, getenv (ENVVAR_NAME), FALSE);
  167.    }
  168.    if (do_default_init)
  169.    {  cci_file_names.stdlibs   = LIBSXX;
  170.       cci_file_names.linker    = LDXX;
  171.       cci_file_names.crtmodule = CRTXX;
  172.       cci_file_names.echo      = ECHOXX;
  173.    }
  174.    TT (cci_M, T_LEAVE; TXT("main"); TS(cci_file_names.executable);
  175.                   TXT("ld");   TS(cci_file_names.linker);
  176.                TXT("crt");  TS(cci_file_names.crtmodule);
  177.                TXT("libs"); TS(cci_file_names.stdlibs);
  178.                   TXT("echo"); TB(cci_file_names.echo));
  179. #endif CAN_LOAD_INCREMENTALLY
  180. }
  181.  
  182. // --------------------------------------------------------------------------
  183. #if defined(CAN_LOAD_INCREMENTALLY) && defined(GNU)
  184. /*
  185.  * The following is really nasty:
  186.  * We want to use the GNU startup module crt1+.o unchanged. Unfortunately:
  187.  *  - this module must be slipped each time in front of the incrementally
  188.  *    loaded object modules, but
  189.  *  - contains an external symbol named '_initfn' which is initialized to a
  190.  *    null pointer and called (resp. the referenced function) after the global
  191.  *    constructors of the added code, and
  192.  *  - we do not use this function pointer for the initialization of the
  193.  *    loaded code.
  194.  * Hence, the second incremental load would fail due to multiple definitions
  195.  * of '_initfn'. Furthermore, we must initialize '_initfn' (it should point to
  196.  * a dummy function), but we can't write this initialization in this module
  197.  * since '_initfn' is not known before the incremental load.
  198.  * The `solution`: 
  199.  *  - Modify the temporary symbol table by making '_initfn' a filelocal symbol
  200.  *    (the original symbol table of the executable remains unchanged).
  201.  *  - This modification is done after each load.
  202.  *  - Since we know the address of '_initfn' from the symbol table, we may
  203.  *    as well use this knowledge to initialize _initfn.
  204.  */
  205. LOCAL void dummy_fct()
  206. {  T_PROC ("cci: dummy_fct")
  207.    TT (cci_VL, T_ENTER);
  208.    TT (cci_VL, T_LEAVE);
  209. }
  210.  
  211. LOCAL void patch_symboltable()
  212. {  T_PROC ("cci: patch_symboltable")
  213.    TT (cci_VL, T_ENTER);
  214.  
  215.    struct exec header;
  216.    int fd;
  217.  
  218.    if ((fd = open (cci_file_names.symtab_file, O_RDWR, 0)) < 0)
  219.       err_raise (err_SYS, err_CCI_OPEN_FAILED, cci_file_names.symtab_file);
  220.    if (read (fd, (void*)&header, sizeof(header)) != sizeof(header))
  221.       err_raise (err_SYS, err_CCI_READ_FAILED, cci_file_names.symtab_file);
  222.    
  223.    off_t sym_offset = N_SYMOFF(header),
  224.      stringbase = N_STROFF(header);
  225.  
  226.    // Is there a better starting point to speed up the search (end of the
  227.    // former symboltable, maybe)? 
  228.    // Current search times seem to be well below 5% of the overall load time.
  229.  
  230.    char* searched    = "__initfn";
  231.    int   searchedlen = strlen (searched);
  232.    char  readbuf[15];
  233.    readbuf[searchedlen] = '\0';
  234.  
  235.    const int SYMBUF_SIZE = 1024 / sizeof(struct nlist);
  236.    struct nlist symbuf[SYMBUF_SIZE];
  237.  
  238.    for (sos_Bool searching = TRUE;  searching; )
  239.    {  if (lseek (fd, sym_offset, SEEK_SET) < 0)
  240.      err_raise (err_SYS, err_CCI_SEEK_FAILED, cci_file_names.symtab_file);
  241.       if (read (fd, (void*)&symbuf, sizeof(symbuf)) != sizeof(symbuf))
  242.      err_raise (err_SYS, err_CCI_READ_FAILED, cci_file_names.symtab_file);
  243.  
  244.       struct nlist *sym_ptr = symbuf;
  245.       for (int idx = SYMBUF_SIZE;  --idx >= 0;  ++ sym_ptr)
  246.       {  if (sym_ptr->n_type == (N_DATA | N_EXT)  &&  sym_ptr->n_un.n_strx > 0)
  247.      {  if (lseek(fd,(off_t)(stringbase+sym_ptr->n_un.n_strx),SEEK_SET) < 0)
  248.            err_raise (err_SYS, err_CCI_SEEK_FAILED,
  249.                    cci_file_names.symtab_file);
  250.         if (read (fd, (void*)&readbuf, searchedlen) <= 0)
  251.            err_raise (err_SYS, err_CCI_READ_FAILED,
  252.                    cci_file_names.symtab_file);
  253.         if (streql (readbuf, searched))
  254.         {  * (vfct_ptr_t*)sym_ptr->n_value = dummy_fct; // set _initfn
  255.            sym_ptr->n_type                &= ~N_EXT;    // clear external bit
  256.  
  257.            if (lseek (fd, sym_offset, SEEK_SET) < 0)
  258.           err_raise (err_SYS, err_CCI_SEEK_FAILED,
  259.                       cci_file_names.symtab_file);
  260.            if (write (fd, (void*)sym_ptr, sizeof(struct nlist))
  261.              < sizeof(struct nlist))
  262.           err_raise (err_SYS, err_CCI_WRITE_FAILED,
  263.                       cci_file_names.symtab_file);
  264.            
  265.            searching = FALSE;
  266.            break;
  267.         }
  268.      }
  269.      if ((sym_offset += sizeof(struct nlist)) >= stringbase)
  270.         err_raise (err_SYS, "symbol __initfn not found", NULL, FALSE);
  271.       } // for (... idx ...)
  272.    } // for (... searching ...)
  273.    close (fd);
  274.  
  275.    TT (cci_VL, T_LEAVE);
  276. }
  277. #endif CAN_LOAD_INCREMENTALLY && GNU
  278.  
  279.  
  280. // --------------------------------------------------------------------------
  281. // conversions for external type cci_Fun
  282. // --------------------------------------------------------------------------
  283.  
  284. sos_String make_string_from_cci_Fun_object (sos_Object f)
  285. {  cci_Fun p1 = make_cci_Fun (f);
  286.    sos_String result
  287.         = smg_String ((sos_Int)p1, FALSE).make_String (TEMP_CONTAINER);
  288.    return result;
  289. }
  290.  
  291. sos_Object make_cci_Fun_object_from_string (sos_String s)
  292. {  sos_Cstring s1 = s.make_Cstring();
  293.    sos_Cstring ptr;
  294.    long        l = strtol (s1, &ptr, 16);
  295.    delete s1;
  296.  
  297.    sos_Object  result = (ptr != s1 AND ptr[0] == 0)
  298.                ? make_cci_Fun_object (cci_Fun (l))
  299.                : NO_OBJECT;
  300.    return result;
  301. }
  302.  
  303.  
  304. // --------------------------------------------------------------------------
  305. // LOCAL: Management of loaded schema implementations
  306. //      (A schema is identified by its associated schema container.)
  307. // --------------------------------------------------------------------------
  308. #define CNT_HTAB_SIZE 128
  309.  
  310. struct cci_CntEntry {
  311.    cci_CntEntry  *next;
  312.    sos_Container ct;
  313. };
  314. LOCAL cci_CntEntry *cnt_htab[CNT_HTAB_SIZE];
  315.  
  316. #ifdef CAN_LOAD_INCREMENTALLY
  317. // The following array is used in 'lookup_files' to prevent from processing
  318. // a schema (container) twice, and afterwards in 'cci_Schema_impl::load' to
  319. // enter the newly loaded schemas (resp. their containers) into the hash table.
  320. LOCAL struct {
  321.    sos_Container *array;
  322.    int         size,
  323.          last_entry; } cnt_array = { NULL, 0, -1 };
  324.  
  325. // *************************************************************************
  326. LOCAL sos_Bool enter_ct (sos_Container ct)
  327. // *************************************************************************
  328. {  T_PROC ("enter_ct")
  329.    TT (cci_L, T_ENTER);
  330.  
  331.    for (int i = 0;  i <= cnt_array.last_entry;  ++ i)
  332.       if (ct EQ cnt_array.array[i])
  333.       {  TT (cci_L, T_LEAVE; TB(FALSE));
  334.      return FALSE;
  335.       }
  336.  
  337.    if (++cnt_array.last_entry EQ cnt_array.size)
  338.    {  sos_Container *tmp;
  339.       if (cnt_array.size)
  340.       {  tmp = new sos_Container[cnt_array.size *= 2];
  341.      bcopy ((char*)cnt_array.array,
  342.         (char*)tmp,
  343.         cnt_array.last_entry * (int)sizeof(sos_Container));
  344.      delete cnt_array.array;
  345.       }
  346.       else
  347.      tmp = new sos_Container[cnt_array.size = 4];
  348.       cnt_array.array = tmp;
  349.    }
  350.    cnt_array.array[cnt_array.last_entry] = ct;
  351.  
  352.    TT (cci_L, T_LEAVE; TB(TRUE));
  353.    return TRUE;
  354. }
  355. #endif CAN_LOAD_INCREMENTALLY
  356.  
  357. // *************************************************************************
  358. LOCAL sos_Bool enter_schema (sos_Container ct, sos_Bool enter_if_new = TRUE)
  359. // *************************************************************************
  360. {  T_PROC ("enter_schema")
  361.    TT (cci_L, T_ENTER);
  362.  
  363.    sos_Bool new_schema;
  364.  
  365.    for (cci_CntEntry **e = &cnt_htab[ct % CNT_HTAB_SIZE];
  366.         *e AND (*e)->ct != ct;
  367.         e = &(*e)->next)
  368.    {}
  369.    if (*e)
  370.       new_schema = FALSE;
  371.    else
  372.    {  new_schema = TRUE;
  373.  
  374.       if (enter_if_new)
  375.       {  *e = new cci_CntEntry;
  376.      (*e)->next = NULL;
  377.      (*e)->ct   = ct;
  378.       }
  379.    }
  380.  
  381.    TT (cci_L, T_LEAVE; TI((int)ct); TB(new_schema));
  382.    return new_schema;
  383. }
  384.  
  385. // *************************************************************************
  386. LOCAL void load_schema (sos_Container ct)
  387. // *************************************************************************
  388. {  T_PROC ("load_schema")
  389.    TT (cci_L, T_ENTER);
  390.  
  391.    // This routine is the entry point to the incremental loading facility
  392.    // for the generated code, in particular via the C::make() calls.
  393.  
  394.    for (cci_CntEntry **e = &cnt_htab[ct % CNT_HTAB_SIZE];
  395.     *e AND (*e)->ct != ct;
  396.     e = &(*e)->next)
  397.    {}
  398.    if (*e == NULL)                // schema not yet loaded
  399.    {  sos_Bool found = FALSE;
  400.       sos_Schema_module    sm  = sos_Schema_module::retrieve (ct);
  401.       sos_Schema_impl_List sil = sm.get_impls();
  402.       if (sil != NO_OBJECT)
  403.      agg_iterate (sil, sos_Schema_impl si)
  404.         if (si.isa (cci_Schema_impl_type))
  405.         {  cci_Schema_impl::make (si).load();
  406.            found = TRUE;
  407.            break;
  408.         }
  409.      agg_iterate_end (sil, si);
  410.       
  411.       if (NOT found)
  412.      err_raise (err_SYS, err_CCI_INC_LOAD_FAILED,
  413.                  sm.get_name().make_Cstring());
  414.    }
  415.    TT (cci_L, T_LEAVE);
  416. }
  417.  
  418. // *************************************************************************
  419. LOCAL inline void schema_is_loaded (sos_Container ct)
  420. // *************************************************************************
  421. {  enter_schema (ct, TRUE);
  422. }
  423.  
  424. #ifdef CAN_LOAD_INCREMENTALLY
  425. // *************************************************************************
  426. LOCAL void lookup_files (sos_Container   ct,
  427.              sos_String_List objects,
  428.              sos_String_List libraries)
  429. // *************************************************************************
  430. {  T_PROC ("cci : lookup_files")
  431.    TT (cci_L, T_ENTER; TXT("container"); TI((int)ct));
  432.  
  433.    sos_Schema_module sm = sos_Schema_module::retrieve (ct);
  434.  
  435.     // first step: (recursively) add file names for imported schemas
  436.     //           not yet loaded
  437.    sos_Imports impl = sm.get_imports();
  438.    if (impl != NO_OBJECT)
  439.       agg_iterate (impl, sos_Schema_module imp)
  440.      sos_Container imp_ct = imp.container();
  441.      if (enter_schema (imp_ct, FALSE)  AND  enter_ct (imp_ct))
  442.         lookup_files (imp_ct, objects, libraries);
  443.       agg_iterate_end (impl, imp);
  444.  
  445.    cci_Schema_impl      si  = cci_Schema_impl::make (NO_OBJECT);
  446.    sos_Schema_impl_List sil = sm.get_impls();
  447.    if (sil != NO_OBJECT)
  448.       agg_iterate (sil, sos_Schema_impl i)
  449.      if (i.isa (cci_Schema_impl_type))
  450.      {  si = cci_Schema_impl::make (i);
  451.         break;
  452.      }
  453.       agg_iterate_end (sil, i);
  454.    
  455.    if (si EQ NO_OBJECT)
  456.       err_raise (err_SYS, err_CCI_INC_LOAD_FAILED,
  457.               sm.get_name().make_Cstring());
  458.  
  459.     // second step: (recursively) add file names for schemas this schema
  460.     //        depends on and which are not yet loaded
  461.    sos_String_List sl = si.get_schemas();
  462.    if (sl != NO_OBJECT)
  463.       agg_iterate (sl, sos_String s)
  464.      sos_Schema_module sm = sos_Schema_module::lookup (s);
  465.      if (sm EQ NO_OBJECT)
  466.         err_raise (err_SYS, err_CCI_UNKNOWN_SCHEMA,
  467.                 sm.get_name().make_Cstring());
  468.  
  469.      sos_Container imp_ct = sm.container();
  470.      if (enter_schema (imp_ct, FALSE)  AND  enter_ct (imp_ct))
  471.         lookup_files (imp_ct, objects, libraries);
  472.       agg_iterate_end (sl, s);
  473.  
  474.     // third step: process the direct dependencies of this schema on
  475.     //           object modules, libraries
  476.    if ((sl = si.get_object_files()) != NO_OBJECT)
  477.       objects += sl;
  478.  
  479.    if ((sl = si.get_libraries()) != NO_OBJECT)
  480.       libraries += sl;
  481.  
  482.    TT (cci_L, T_LEAVE);
  483. }
  484. #endif CAN_LOAD_INCREMENTALLY
  485.  
  486.  
  487. // --------------------------------------------------------------------------
  488. // class cci_Schema_impl
  489. // --------------------------------------------------------------------------
  490. // *************************************************************************
  491. cci_Schema_impl cci_Schema_impl::make_impl (sos_Schema_module s)
  492. // *************************************************************************
  493. {  T_PROC ("cci_Schema_impl::make_impl")
  494.    TT (cci_H, T_ENTER);
  495.  
  496.    cci_Schema_impl result;
  497.    sos_Bool found = FALSE;
  498.  
  499.    sos_Schema_impl_List impls = s.get_impls();
  500.    if (impls == NO_OBJECT)
  501.    {  impls = sos_Schema_impl_List::create (s.container());
  502.       s.set_impls (impls);
  503.    }
  504.    else
  505.       agg_iterate (impls, sos_Schema_impl impl)
  506.          if (impl.isa (cci_Schema_impl_type))
  507.      {  found = TRUE;
  508.         result = cci_Schema_impl::make (impl);
  509.         break;
  510.      }
  511.       agg_iterate_end (impls, impl);
  512.  
  513.    if (NOT found)
  514.    {  result = cci_Schema_impl::create (s.container());
  515.       impls.append (result);
  516.    }
  517.  
  518.    TT (cci_H, T_LEAVE);
  519.    return result;
  520. }
  521.  
  522.  
  523. // **************************************************************************
  524. void cci_Schema_impl::load ()
  525. // **************************************************************************
  526. {  T_PROC ("cci_Schema_impl::load")
  527.    TT (cci_H, T_ENTER);
  528.  
  529.    if (NOT enter_schema (self.container(), FALSE))
  530.    {  TT (cci_H, T_LEAVE);
  531.       return;
  532.    }
  533.    
  534. #ifndef CAN_LOAD_INCREMENTALLY
  535.    err_raise (err_SYS, err_CCI_INC_LOAD_NOT_IMPL, NULL, FALSE);
  536.    sos_Offset o = self.offset(); // only to avoid AT&T compiler warnings!
  537. #else
  538.    int fd;
  539.    struct exec header;
  540.    
  541.    if (cci_file_names.executable EQ NULL)
  542.       err_raise (err_SYS, err_CCI_NOT_INITIALIZED, NULL, FALSE);
  543.   
  544.    cnt_array.last_entry = -1;
  545.    enter_ct (self.container());
  546.  
  547.    sos_String_List objects = sos_String_List::create (TEMP_CONTAINER, FALSE);
  548.    sos_String_List libs    = sos_String_List::create (TEMP_CONTAINER, FALSE);
  549.  
  550.    int hidden_objects = 1;
  551.    objects.append (smg_String(cci_file_names.crtmodule)
  552.               .make_String (TEMP_CONTAINER));
  553.  
  554.    lookup_files (self.container(), objects, libs);
  555.  
  556.    if (objects.card() EQ hidden_objects)
  557.       err_raise (err_SYS, err_CCI_INC_LOAD_FAILED, NULL, FALSE);
  558.  
  559.    if (cci_file_names.symtab_file EQ NULL)
  560.    {  smg_String tmpfile = smg_String("") + sos_tempdir + "/sosdm.XXXXXX";
  561.       cci_file_names.symtab_file = tmpfile.make_Cstring (SMG_TRANSFER);
  562.       mktemp (cci_file_names.symtab_file);
  563.  
  564.       tmpfile = smg_String("") + sos_tempdir + "/sosdf.XXXXXX";
  565.       cci_file_names.tmpfile = tmpfile.make_Cstring (SMG_TRANSFER);
  566.       mktemp (cci_file_names.tmpfile);
  567.  
  568.       TT (cci_M, TXT("tmp.symtab"); TS(cci_file_names.symtab_file);
  569.          TXT("tmp.file");   TS(cci_file_names.tmpfile));
  570.  
  571.       smg_String cmd = smg_String("ln -s ") + cci_file_names.executable + " "
  572.                         + cci_file_names.symtab_file;
  573.       if (system (cmd.make_Cstring (SMG_BORROW)))
  574.      err_raise (err_SYS, err_CCI_LINK_FAILED, NULL, FALSE);
  575.    }
  576.  
  577.    unsigned   size     = 0;
  578.    smg_String cmd_head = smg_String("umask 111;")
  579.              + cci_file_names.linker
  580.              + " -N -A " + cci_file_names.symtab_file
  581.              + " -T ";
  582.    smg_String cmd_tail = smg_String(" -o ") + cci_file_names.tmpfile;
  583.  
  584.    agg_iterate (objects, sos_String on)
  585.    {  smg_String  obj_module = on;
  586.       sos_Cstring obj_name   = obj_module.make_Cstring (SMG_BORROW);
  587.  
  588.       if ((fd = open (obj_name, O_RDONLY, 0)) < 0)
  589.      err_raise (err_SYS, err_CCI_OPEN_FAILED, obj_name);
  590.       if (read (fd, (void*) &header, sizeof (header)) != sizeof (header))
  591.      err_raise (err_SYS, err_CCI_READ_HEADER_FAILED, obj_name);
  592.  
  593.       size     += header.a_text + header.a_data + header.a_bss;
  594.       cmd_tail += smg_String(" ") + obj_module;
  595.  
  596.       close (fd);
  597.  
  598.       if (cci_file_names.echo  AND  --hidden_objects < 0)
  599.      cerr << "...loading " << obj_name << "\n";
  600.    }
  601.    agg_iterate_end (objects, on);
  602.  
  603.    agg_iterate (libs, sos_String ln)
  604.       cmd_tail += smg_String(" ") + ln;
  605.    agg_iterate_end (libs, ln);
  606.  
  607.    cmd_tail += smg_String(" ") + cci_file_names.stdlibs;
  608.  
  609. #ifdef EXEC_PAGESIZE
  610.    int pagsiz = EXEC_PAGESIZE;
  611. #elif defined(PAGSIZ)
  612.    int pagsiz = PAGSIZ;
  613. #else
  614.    int pagsiz = getpagesize();
  615. #endif
  616.  
  617.    if (size > 81920)    // Add 8K in case of bigger files to increase the
  618.       size += 8192;    // chance that the first size guess will suffice.
  619.  
  620.    unsigned actual_size;// Repeat until size >= actual size.
  621.    char     *obj_addr;    // (The first guess might be to small because the
  622.    for (;;)         //  size of the BSS-Segment and the size of code
  623.             //  loaded from libraries is not yet known.)
  624.    {  size += pagsiz - 1;
  625.       char *allocated = new char[size];
  626.  
  627.       obj_addr = (char*)( ((unsigned)allocated + pagsiz - 1) & ~(pagsiz-1) );
  628.       size -= obj_addr - allocated;
  629.       // place additional object modules on page boundary
  630.  
  631.       smg_String ldcmd = cmd_head + smg_String((sos_Int)obj_addr, FALSE)
  632.                   + cmd_tail;
  633.  
  634.       TT (cci_M, TXT("load command"); TS(ldcmd.make_Cstring (SMG_BORROW)));
  635.  
  636.       struct rlimit core_limit;
  637.       getrlimit (RLIMIT_CORE, &core_limit);
  638.       int cur_limit = core_limit.rlim_cur;
  639.       core_limit.rlim_cur = 0;
  640.       setrlimit (RLIMIT_CORE, &core_limit); 
  641.      // suppress core file creation temporarily
  642.  
  643.       int error_status = system (ldcmd.make_Cstring (SMG_BORROW));
  644.  
  645.       core_limit.rlim_cur = cur_limit;
  646.       setrlimit (RLIMIT_CORE, &core_limit);
  647.  
  648.       if (error_status) 
  649.       {  unlink (cci_file_names.tmpfile);
  650.      err_raise (err_SYS, err_CCI_LOAD_FAILED, NULL, FALSE);
  651.       }
  652.  
  653.       fd = open (cci_file_names.tmpfile, O_RDONLY, 0);
  654.       read (fd, (void*) &header, sizeof (header));
  655.       close (fd);
  656.  
  657.       actual_size = header.a_text + header.a_data + header.a_bss;
  658.       if (actual_size <= size) break;
  659.  
  660.       TT (cci_M, TXT("...repeat loading");
  661.          TXT("size guess"); TI(size);
  662.          TXT("actual size"); TI(actual_size));
  663.  
  664.       delete allocated;
  665.       size = actual_size;
  666.    }
  667.  
  668.    smg_String cmd = smg_String("rm ") + cci_file_names.symtab_file
  669.                  + ";mv " + cci_file_names.tmpfile
  670.                  + " "    + cci_file_names.symtab_file;
  671.    if (system (cmd.make_Cstring (SMG_BORROW)))
  672.       err_raise (err_SYS, err_CCI_MOVE_FAILED, NULL, FALSE);
  673.  
  674.    fd = open (cci_file_names.symtab_file, O_RDONLY, 0);
  675.    if (lseek (fd, (off_t)N_TXTOFF(header), SEEK_SET) < 0)
  676.       err_raise (err_SYS, err_CCI_SEEK_FAILED, NULL, FALSE);
  677.  
  678.    if (read (fd, obj_addr, actual_size) != actual_size)
  679.       err_raise (err_SYS, err_CCI_READ_FAILED, NULL, FALSE);
  680.    close (fd);
  681.  
  682. #ifdef MUST_MPROTECT
  683.    if (mprotect (obj_addr, actual_size, PROT_READ|PROT_EXEC|PROT_WRITE))
  684.       err_raise (err_SYS, err_CCI_MKEXEC_FAILED, NULL, FALSE);
  685. #endif MUST_MPROTECT
  686.  
  687.    patch_symboltable();
  688.  
  689.    (* (vfct_ptr_t)obj_addr)();        // call startup routine of crtmodule.
  690.  
  691.    for (int i = 0;  i <= cnt_array.last_entry;  ++ i)
  692.       schema_is_loaded (cnt_array.array[i]);
  693.  
  694. #endif CAN_LOAD_INCREMENTALLY
  695.    TT (cci_H, T_LEAVE);
  696. }
  697.  
  698. // *************************************************************************
  699. void cci_Schema_impl::local_assign (cci_Schema_impl dest, sos_Object src_o)
  700. // *************************************************************************
  701. {  T_PROC ("cci_Schema_impl::local_assign")
  702.    TT (cci_M, T_ENTER);
  703.  
  704.    cci_Schema_impl src = cci_Schema_impl::make (src_o);
  705.  
  706.    dest.get_object_files().assign (src.get_object_files());
  707.    dest.get_libraries().assign (src.get_libraries());
  708.    dest.get_schemas().assign (src.get_schemas());
  709.  
  710.    TT (cci_M, T_LEAVE);
  711. }
  712.  
  713. // *************************************************************************
  714. void cci_Schema_impl::local_initialize (cci_Schema_impl impl)
  715. // *************************************************************************
  716. {  T_PROC ("cci_Schema_impl::local_initialize")
  717.    TT (cci_M, T_ENTER);
  718.  
  719.    sos_Container ct = impl.container();
  720.  
  721.    impl.set_object_files (sos_String_List::create (ct, TRUE));
  722.    impl.set_libraries (sos_String_List::create (ct, TRUE));
  723.    impl.set_schemas (sos_String_List::create (ct, TRUE));
  724.  
  725.    TT (cci_M, T_LEAVE);
  726. }
  727.  
  728. // *************************************************************************
  729. void cci_Schema_impl::local_finalize (cci_Schema_impl impl)
  730. // *************************************************************************
  731. {  T_PROC ("cci_Schema_impl::local_finalize")
  732.    TT (cci_M, T_ENTER);
  733.  
  734.    impl.get_object_files().destroy();
  735.    impl.get_libraries().destroy();
  736.    impl.get_schemas().destroy();
  737.  
  738.    TT (cci_M, T_LEAVE);
  739. }
  740.  
  741.  
  742. // --------------------------------------------------------------------------
  743. // class cci_Schema_impl : Management of dynamic type representation objects
  744. // --------------------------------------------------------------------------
  745. #define MAKE_OBJ_HTAB_SIZE 1024
  746.  
  747. struct cci_MakeObjEntry {
  748.    cci_MakeObjEntry *next;
  749.    sos_Id           f, t;
  750.    cci_Make_obj     obj;
  751. };
  752.  
  753. LOCAL cci_MakeObjEntry *make_obj_htab[MAKE_OBJ_HTAB_SIZE];
  754.  
  755. // *************************************************************************
  756. cci_Make_obj cci_Schema_impl::get_make_obj (sos_Id t, sos_Id f)
  757. // *************************************************************************
  758. {  T_PROC ("cci_Schema_impl::get_make_obj")
  759.    TT (cci_L, T_ENTER);
  760.  
  761.    if (f.offset() == 0  AND  (sos_Int)f.container() == 0) // type of NO_OBJECT
  762.       f = t;
  763.  
  764.    int hash = (f.offset() ^ (sos_Int) f.container()
  765.             ^ ((t.offset() ^ (sos_Int) t.container()) >> 4))
  766.           % MAKE_OBJ_HTAB_SIZE;
  767.  
  768.    cci_Make_obj result;
  769.  
  770.    for (sos_Bool first_lookup = TRUE;  ;  first_lookup = FALSE)
  771.    {  for (cci_MakeObjEntry **e = &make_obj_htab[hash];
  772.        *e AND ((*e)->f != f OR (*e)->t != t);
  773.        e = &(*e)->next)
  774.       {}
  775.  
  776.       if (*e)
  777.       {  result = (*e)->obj;
  778.      break;
  779.       }
  780.       else if (first_lookup)
  781. #if BOOT
  782.      err_raise (err_SYS, err_CCI_INVALID_MAKE,
  783.                  "cci_Schema_impl::get_make_obj", FALSE);
  784. #else
  785.      load_schema (f.container());
  786. #endif
  787.       else
  788.       {
  789.      sos_Type tp = sos_Type::make (sos_Typed_id::make (f));
  790.      sos_Type rt = tp.root();
  791. #ifdef ATT
  792.      if (tp.operator!=(rt))
  793. #else
  794.      if (tp != rt)
  795. #endif
  796.         result = cci_Schema_impl::get_make_obj (t, rt.typed_id().get_id());
  797.      else
  798.         err_raise (err_SYS, err_CCI_INVALID_MAKE,
  799.                 "cci_Schema_impl::get_make_obj", FALSE);
  800.      break;
  801.       }
  802.    }
  803.    TT (cci_L, T_LEAVE);
  804.    return result;
  805. }
  806.  
  807. // *************************************************************************
  808. void cci_Schema_impl::enter_make_obj (sos_Id t, sos_Id f, cci_Make_obj obj)
  809. // *************************************************************************
  810. {  T_PROC ("cci_Schema_impl::enter_make_obj")
  811.    TT (cci_L, T_ENTER);
  812.  
  813.    schema_is_loaded (f.container());
  814.  
  815.    int hash = (f.offset() ^ (sos_Int) f.container()
  816.             ^ ((t.offset() ^ (sos_Int) t.container()) >> 4))
  817.           % MAKE_OBJ_HTAB_SIZE;
  818.  
  819.    for (cci_MakeObjEntry **e = &make_obj_htab[hash];
  820.     *e AND ((*e)->f != f OR (*e)->t != t);
  821.         e = &((*e)->next))
  822.    {}
  823.  
  824.    if (! *e)
  825.    {  *e = new cci_MakeObjEntry;
  826.       (*e)->next = NULL;
  827.       (*e)->f    = f;
  828.       (*e)->t    = t;
  829.       (*e)->obj  = obj;
  830.    }
  831.    TT (cci_L, T_LEAVE);
  832. }
  833.  
  834.  
  835. // --------------------------------------------------------------------------
  836. // class cci_Schema_impl : C++ method implementation management
  837. // --------------------------------------------------------------------------
  838. #define FUN_HTAB_SIZE 1024
  839.  
  840. struct cci_Fun_entry {
  841.    cci_Fun_entry* next;
  842.    sos_Id  m;
  843.    cci_Fun fun;
  844. };
  845. LOCAL cci_Fun_entry *fun_htab[FUN_HTAB_SIZE];
  846.  
  847. // *************************************************************************
  848. cci_Fun cci_Schema_impl::get_fun (sos_Id m)
  849. // *************************************************************************
  850. {  T_PROC ("cci_Schema_impl::get_fun")
  851.    TT (cci_L, T_ENTER);
  852.  
  853.    load_schema (m.container());
  854.  
  855.    int hash = (m.offset() ^ (sos_Int) m.container()) % FUN_HTAB_SIZE;
  856.  
  857.    for (cci_Fun_entry **e = &fun_htab[hash];
  858.     *e AND (*e)->m != m;
  859.     e = &(*e)->next)
  860.    {}
  861.  
  862.    cci_Fun fun;
  863.    if (*e)
  864.       fun = (*e)->fun;
  865.    else
  866.       err_raise (err_SYS, err_CCI_INVALID_METHOD,
  867.          "cci_Schema_impl::get_fun", FALSE);
  868.  
  869.    TT (cci_L, T_LEAVE);
  870.    return fun;
  871. }
  872.  
  873. // *************************************************************************
  874. void cci_Schema_impl::enter_fun (sos_Id m, cci_Fun fun)
  875. // *************************************************************************
  876. {  T_PROC ("cci_Schema_impl::enter_fun")
  877.    TT (cci_L, T_ENTER);
  878.  
  879.    int hash = (m.offset() ^ (sos_Int) m.container()) % FUN_HTAB_SIZE;
  880.  
  881.    for (cci_Fun_entry **e = &fun_htab[hash];
  882.     *e AND NOT ((*e)->m == m);
  883.         e = &((*e)->next))
  884.    {}
  885.    if (! *e)
  886.    {  *e = new cci_Fun_entry;
  887.       (*e)->next = NULL;
  888.       (*e)->m = m;
  889.       (*e)->fun = fun;
  890.    }
  891.    TT (cci_L, T_LEAVE);
  892. }
  893.  
  894. // *************************************************************************
  895. void cci_Schema_impl::enter_string_io (sos_Id  et,
  896.                        cci_IO_fun from_extern,
  897.                        cci_IO_fun to_extern)
  898. // *************************************************************************
  899. {  T_PROC ("cci_Schema_impl::enter_string_io")
  900.    TT (cci_L, T_ENTER);
  901.  
  902.    sos_Id et1 = sos_Id::make (et.container(), et.offset() + 1);
  903.  
  904.    cci_Schema_impl::enter_fun (et , (cci_Fun)from_extern);
  905.    cci_Schema_impl::enter_fun (et1, (cci_Fun)to_extern);
  906.  
  907.    TT (cci_L, T_LEAVE);
  908. }
  909.  
  910.  
  911. // --------------------------------------------------------------------------
  912. // class cci_Schema_impl : generic conversions for external types
  913. // --------------------------------------------------------------------------
  914.  
  915. typedef sos_Object (*cci_cnv_from_string)(sos_String);
  916. typedef sos_String (*cci_cnv_to_string)(sos_Object);
  917.  
  918. // *************************************************************************
  919. sos_Object cci_Schema_impl::extern_object_from_string (sos_Type   tp,
  920.                                sos_String s)
  921. // *************************************************************************
  922. {  T_PROC ("cci_Schema_impl::extern_object_from_string")
  923.    TT (cci_H, T_ENTER);
  924.  
  925.    sos_Id id  = tp.typed_id().get_id();
  926.    sos_Id id1 = sos_Id::make (id.container(), id.offset() + 1);
  927.  
  928.    sos_Object result
  929.            = (* (cci_cnv_from_string)(cci_Schema_impl::get_fun (id1)) ) (s);
  930.  
  931.    TT (cci_H, T_LEAVE);
  932.    return result;
  933. }
  934.  
  935. // *************************************************************************
  936. sos_String cci_Schema_impl::string_from_extern_object (sos_Object o)
  937. // *************************************************************************
  938. {  T_PROC ("cci_Schema_impl::string_from_extern_object")
  939.    TT (cci_H, T_ENTER);
  940.  
  941.    sos_Id id = o.typed_id().get_tp();
  942.  
  943.    sos_String result
  944.         = (* (cci_cnv_to_string)(cci_Schema_impl::get_fun (id)) ) (o);
  945.  
  946.    TT (cci_H, T_LEAVE);
  947.    return result;
  948. }
  949.  
  950.  
  951. // --------------------------------------------------------------------------
  952. // class cci_Method_impl
  953. // --------------------------------------------------------------------------
  954. // *************************************************************************
  955. cci_Method_impl cci_Method_impl::make_impl (sos_Method m)
  956. // *************************************************************************
  957. {  T_PROC ("cci_Method_impl::make_impl")
  958.    TT (cci_H, T_ENTER);
  959.  
  960.    cci_Method_impl result;
  961.    sos_Bool found = FALSE;
  962.  
  963.    sos_Method_impl_List impls = m.get_impls();
  964.    if (impls == NO_OBJECT)
  965.    {  impls = sos_Method_impl_List::create (m.container());
  966.       m.set_impls (impls);
  967.    }
  968.    else
  969.    {  agg_iterate (impls, sos_Method_impl impl)
  970.          if (impl.isa (cci_Method_impl_type))
  971.      {  found = TRUE;
  972.         result = cci_Method_impl::make (impl);
  973.         break;
  974.      }
  975.       agg_iterate_end (impls, impl);
  976.    }
  977.  
  978.    if (NOT found)
  979.    {  result = cci_Method_impl::create (m.container());
  980.       impls.append (result);
  981.    }
  982.    TT (cci_H, T_LEAVE);
  983.    return result;
  984. }
  985.  
  986. // *************************************************************************
  987. void cci_Method_impl::enter_fun (cci_Fun fun)
  988. // *************************************************************************
  989. {  T_PROC ("cci_Method_impl::enter_fun")
  990.    TT (cci_L, T_ENTER);
  991.  
  992.    cci_Schema_impl::enter_fun (self.typed_id().get_id(), fun);
  993.  
  994.    TT (cci_L, T_LEAVE);
  995. }
  996.  
  997. // *************************************************************************
  998. sos_Object cci_Method_impl::execute (sos_Object o, sos_Object_Array p)
  999. // *************************************************************************
  1000. {  T_PROC ("cci_Method_impl::execute")
  1001.    TT (cci_H, T_ENTER);
  1002.  
  1003.    sos_Object result;
  1004.    cci_Fun f = cci_Schema_impl::get_fun (self.typed_id().get_id());
  1005.  
  1006.    result = (*f) (o, p);
  1007.  
  1008.    TT (cci_H, T_LEAVE);
  1009.    return result;
  1010. }
  1011.  
  1012. // *************************************************************************
  1013. sos_String cci_Method_impl::operator_string (sos_String op_name)
  1014. // *************************************************************************
  1015. {  T_PROC ("cci_Method_impl::operator_string")
  1016.    TT (cci_H, T_ENTER);
  1017.  
  1018.    smg_String op_string = op_name;
  1019.    smg_String result_string;
  1020.    sos_String result;
  1021.  
  1022.         if (op_string.equal ("+")  ) result_string = "__plus";
  1023.    else if (op_string.equal ("-")  ) result_string = "__minus";
  1024.    else if (op_string.equal ("*")  ) result_string = "__times";
  1025.    else if (op_string.equal ("/")  ) result_string = "__div";
  1026.    else if (op_string.equal ("%")  ) result_string = "__rem";
  1027.    else if (op_string.equal ("^")  ) result_string = "__xor";
  1028.    else if (op_string.equal ("&")  ) result_string = "__and";
  1029.    else if (op_string.equal ("|")  ) result_string = "__or";
  1030.    else if (op_string.equal ("~")  ) result_string = "__not";
  1031.    else if (op_string.equal ("!")  ) result_string = "__logical_not";
  1032.    else if (op_string.equal ("=")  ) result_string = "__assign";
  1033.    else if (op_string.equal ("<")  ) result_string = "__less";
  1034.    else if (op_string.equal (">")  ) result_string = "__greater";
  1035.    else if (op_string.equal ("+=") ) result_string = "__plus_assign";
  1036.    else if (op_string.equal ("-=") ) result_string = "__minus_assign";
  1037.    else if (op_string.equal ("*=") ) result_string = "__times_assign";
  1038.    else if (op_string.equal ("/=") ) result_string = "__div_assign";
  1039.    else if (op_string.equal ("%=") ) result_string = "__rem_assign";
  1040.    else if (op_string.equal ("^=") ) result_string = "__xor_assign";
  1041.    else if (op_string.equal ("&=") ) result_string = "__and_assign";
  1042.    else if (op_string.equal ("|=") ) result_string = "__or_assign";
  1043.    else if (op_string.equal ("<<") ) result_string = "__shift_left";
  1044.    else if (op_string.equal (">>") ) result_string = "__shift_right";
  1045.    else if (op_string.equal (">>=")) result_string = "__shift_right_assign";
  1046.    else if (op_string.equal ("<<=")) result_string = "__shift_left_assign";
  1047.    else if (op_string.equal ("==") ) result_string = "__equal";
  1048.    else if (op_string.equal ("!=") ) result_string = "__not_equal";
  1049.    else if (op_string.equal ("<=") ) result_string = "__less_equal";
  1050.    else if (op_string.equal (">=") ) result_string = "__greater_equal";
  1051.    else if (op_string.equal ("&&") ) result_string = "__logical_and";
  1052.    else if (op_string.equal ("||") ) result_string = "__logical_or";
  1053.    else if (op_string.equal ("++") ) result_string = "__increment";
  1054.    else if (op_string.equal ("--") ) result_string = "__decrement";
  1055.    else if (op_string.equal (",")  ) result_string = "__comma";
  1056.    else if (op_string.equal ("->*")) result_string = "__member_access";
  1057.    else if (op_string.equal ("->") ) result_string = "__access";
  1058.    else if (op_string.equal ("()") ) result_string = "__function";
  1059.    else if (op_string.equal ("[]") ) result_string = "__index";
  1060.    else result_string = op_string;
  1061.  
  1062.    result = result_string.make_String (TEMP_CONTAINER);
  1063.  
  1064.    TT (cci_H, T_LEAVE);
  1065.    return result;
  1066. }
  1067.